package com.gitee.faster.webdav.kernel.protocol.dispatcher;

import com.gitee.faster.webdav.common.constant.Constants;
import com.gitee.faster.webdav.common.constant.HttpHeaderEnum;
import com.gitee.faster.webdav.common.constant.MethodEnum;
import com.gitee.faster.webdav.common.structure.RangeValue;
import com.gitee.faster.webdav.exception.NotFoundException;
import com.gitee.faster.webdav.kernel.protocol.HttpExchange;
import com.gitee.faster.webdav.kernel.resource.Resource;
import lombok.extern.slf4j.Slf4j;
import org.smartboot.http.common.enums.HttpStatus;
import org.smartboot.http.common.utils.Mimetypes;

/**
 * @author hongda.li
 */
@Slf4j
public class MethodDispatcherGet implements MethodDispatcher {

    @Override
    public MethodEnum supported() {
        return MethodEnum.GET;
    }

    @Override
    public void dispatch(HttpExchange httpExchange) {
        Resource resource = httpExchange.getResource();

        // 资源名称
        String resourceName = resource.getName();

        log.info("资源名称 : {}", resourceName);

        // 文件不存在或非文件
        if (!resource.exists() || !resource.isFile()) {
            log.warn("文件不存在或非文件类型 : {}", resourceName);
            throw new NotFoundException(resourceName);
        }

        // 设置响应类型
        httpExchange.setContentType(Mimetypes.getInstance().getMimetype(resourceName));

        // 允许断点续传
        httpExchange.addHeader(HttpHeaderEnum.ACCEPT_RANGES.getHeader(), Constants.BYTES);

        // 获取断点续传请求头
        String rangeHeader = httpExchange.getHeaderValue().getStr(HttpHeaderEnum.RANGE.getHeader());

        // 解析可能存在的请求头
        RangeValue rangeValue = RangeValue.from(rangeHeader, resource.length());

        if (rangeValue == null) {
            log.info("开始全量读取");
            this.downloadAll(httpExchange, resource);
        } else {
            log.info("开始断点续传");
            this.downloadPart(httpExchange, resource, rangeValue);
        }
    }

    private void downloadPart(HttpExchange accessor, Resource resource, RangeValue rangeValue) {
        long start = rangeValue.start();
        long end = rangeValue.end();
        if (start > end) {
            log.warn("不合法的Range请求头 : {}", rangeValue);
            accessor.setHttpStatus(HttpStatus.NO_CONTENT);
            return;
        }

        // 本次传输的文件总大小
        long contentLength = end - start + 1;
        accessor.setContentLength(contentLength);

        // 返回码需要为 206，代表只处理了部分请求，响应了部分数据
        accessor.setHttpStatus(HttpStatus.PARTIAL_CONTENT);

        // 设置此次响应返回的数据范围
        String range = String.format(Constants.CONTENT_RANGE_TEMPLATE, start, end, resource.length());
        accessor.addHeader(HttpHeaderEnum.CONTENT_RANGE.getHeader(), range);

        accessor.getRepository().downloadPart(resource, accessor.getOutputStream(), rangeValue);
    }

    private void downloadAll(HttpExchange accessor, Resource resource) {
        // 设置状态码
        accessor.setHttpStatus(HttpStatus.OK);

        // 设置文件总大小
        accessor.setContentLength(resource.length());

        // 全量下载
        accessor.getRepository().download(resource, accessor.getOutputStream());
    }
}
